iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
0
Software Development

Dart 語言 - 開啟 Flutter 的鑰匙系列 第 19

Day19:靜態變數 (Static variable)、靜態方法 (Static method) 以及 頂層函數 (Top-level functions)

  • 分享至 

  • xImage
  •  

在前面的文章中,我們知道知道每一個類別裡面都包含其屬性及方法,我們必須透過實例化的動作,才能夠取用。

例如:

class Log {
	String message;
	Log(this.message);

	void sendMessage(){
		//send message
		print('message sent');
	}
}

void main(){
	final log = Log('System boot');
	print(log.message);
	log.sendMessage();
}

這裡面的屬性、函數,都是在我們建立類別之後才去初始化的。所以我們才能從類別的實例去取用它們。

那麼,有沒有什麼方法能夠不將類別實例化,直接取用該類別的屬性或是函數呢?

有,靜態變數(static variable)、靜態方法(static method)。

Static 關鍵字

Dart 提供了 static 關鍵字,讓類別的屬性、函數轉變為全域的變數以及方法。

靜態變數 (Static variable)

將類別的屬性加上 static ,該屬性成為全域變數。

範例:替 Log 類加上一個靜態變數 tag。

class Log {
	static String tag;

	String message;
	Log(this.message);

	void sendMessage(){
		//send message
		print('message sent');
	}
}

我們可以直接使用它,而不經過實例化 Log 類。

void main(){
	final tag = Log.tag;
	print(tag);
}
// null

靜態變數的初始化

由上面的範例得知,當靜態變數未設定初始值,則值為 null。

修改一下上面的範例,讓該靜態變數是由外部取得。我們來看一下靜態變數的初始化。

class Log {
	static String tag = TAG('Dart').name;

	String message;
	Log(this.message);

	void sendMessage(){
		//send message
		print('message sent');
	}
}

class TAG{
	String name;
	TAG(this.name){
		print('Tag is $name');
	}
}
void main(){
	final tag1 = Log.tag;
	print(tag1);
	final tag2 = Log.tag;
	print(tag2);
	Log.tag = 'Dart2';
	print(Log.tag);
}
//Tag is Dart
//Dart
//Dart
//Dart2

發現什麼?

靜態變數只有在第一次使用的時候進行初始化,之後每次呼叫,都只是從記憶體取出該值而已。

覆寫靜態變數之後,每次取值都是新的值。

靜態常數值 (static const variable)

我們亦可以在靜態變數上加上 const 來宣告該靜態變數的值為常數。

class Log{
	static const bool isDebug = true;

	static String tag = TAG('Dart').name;

	String message;
	Log(this.message);

	void sendMessage(){
		//send message
		if(isDebug){
			print('message sent');
		}
	}
}

靜態方法 (static method)

如同靜態變數,將類別中的方法加上 static 關鍵字即成為靜態方法,靜態方法是可以不需要實例化類別而進行操作的方法。

例如,我們可以將上例的 sendMessage() 改為靜態方法

class Log {
  static const bool isDebug = true;
  static String tag = TAG('Dart').name;

  String message;
  Log(this.message);

  static void sendMessage(Log log){
    //send message
    print('[$tag]:${log.message}');
  }
}
void main(){
	Log.sendMessage(Log('Message test'));
}
//[Dart]:Message test
  • 類別方法加上 static 變成靜態方法之後,沒有辦法直接取得類別屬性 String message
  • 我們將 sendMessage 的引數改為 Log log ,將整個類別傳進來,就可以直接在靜態方法 seneMessage 中取用傳入的 log 類別。
  • 在靜態方法中,可以直接參考同一個類別的靜態變數。如: static String tag

有沒有發現,其實靜態方法不一定需要存在於類別內,因為我們可以將整個類別當作引數傳入,那麼這整個靜態方法就不一定需要擺在類別裡面了。

我們可以將靜態方法搬出類別嗎?

不行,但是 Dart 提供了頂層函數 (top-level functions) 可以達成一樣的目的。

頂層函數 (top-level functions)

將上方的範例中的靜態方法改為頂層函數:

void sendMessage(Log log){
  //send message
  print('[${Log.tag}]:${log.message}');
}

class Log {
  static const bool isDebug = true;
  static String tag = TAG('Dart').name;

  String message;
  Log(this.message);
}
  1. 將靜態函數搬出類別。
  2. static 關鍵字移除。
  3. 將原本函數裡使用的靜態變數加上類別名稱。
  4. 完成。

如此,就可以將靜態方法改為頂層函數。

呼叫方法:只要直接使用函數的名稱,即可呼叫該函數。

void main(){
	sendMessage(Log('Message test'));
}
//[Dart]:Message test
  • 其實,我們一開始看到的 main() 也是屬於頂層函數,因為他不屬於任何類別。

頂層變數 (top-level variables)、頂層常數 (top-level constants)

有頂層函數,當然就有頂層變數以及頂層常數。

定義頂層變數、頂層常數的方式也很簡單。將原本定義在類別內的靜態變數、靜態常數移出類別,並將 static 關鍵字移除。

const bool isDebug = true;
String tag= TAG('Dart').name;

void sendMessage(Log log){
  //send message
  print('[$tag]:${log.message}');
}

class Log {
  String message;
  Log(this.message);
}

如此,類別內就只剩下非靜態的屬性、方法。變得單純許多。

小結

靜態變數、靜態方法在程式語言中是一定會存在的項目,使用靜態項目常常被質疑違反了物件導向的設計。因為不需要將類別實例化就可以使用該變數或方法。本篇文章不討論使用的好處與壞處,純粹只是介紹靜態項目的用法。

在 Effective Dart 提到,避免建立一個類別只存在一個靜態項目,若是有這樣使用靜態項目的需求,可以改用頂層函數、頂層變數、頂層常數來替代。

AVOID defining a class that contains only static members.


上一篇
Day18:Mixin
下一篇
Day20:泛型 (Generic)
系列文
Dart 語言 - 開啟 Flutter 的鑰匙30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言